knitr::opts_chunk$set(echo = TRUE)
library(readxl)
library(plyr)
library(tibble)
library(dplyr)
library(tidyverse)
library(stringr)
library(knitr)
library(forcats)
library(ggplot2)
library(hrbrthemes) #for ggplot2
library(bibliometrix)
library(igraph)
Data loading
# manually extracted data
xldata <- "./Data_extraction_postcrosschecking.xlsx"
# bibliometric data
bib <- convert2df("./bibliometric.bib", dbsource = "scopus", format = "bibtex")
Data organisation
Splitting list of tabs into separate dataframes
excel_sheets(path = xldata)
tab_names <- excel_sheets(path = xldata)
# creating a list of dataframes per tab
list_all <- lapply(tab_names, function(x) read_excel(path = xldata, sheet = x))
# assigning tab names to each dataframe
names(list_all) <- tab_names
# get dataframes out of list
list2env(list_all, .GlobalEnv)
Addressing objectives 1 and 2
Map the SR literature across disciplines e.g., the types of environmental exposures and traits synthesised, the proportion of SRs that examine inter- versus trans-generational effects, and which disciplines dominate the non-genetic inheritance SR literature. The map will highlight gaps in the literature that remain to be synthesised or have very few SRs.
Present discipline-specific research patterns by summarising commonalities and disparities between disciplines (e.g., do SRs of specific environmental exposures dominate one discipline and not others? Do some disciplines focus on inter-generational effects, and another on trans-generational effects?).
Percent of SR’s within disciplines
count_discipline <- Review_info %>%
count(discipline_code) %>%
arrange(desc(n))
percent_discipline <- count_discipline %>%
mutate(percent = (n/sum(n)) * 100)
percent_discipline$discipline_code <- factor(percent_discipline$discipline_code,
level = percent_discipline$discipline_code[order(percent_discipline$n, decreasing = FALSE)])
ggplot(percent_discipline, aes(x = discipline_code, y = percent)) + geom_col(aes(fill = ""),
width = 0.7) + theme_light() + coord_flip() + scale_y_continuous(name = "Percent") +
xlab("Discipline") + scale_fill_manual(values = c("#919191")) + theme(legend.position = "none",
axis.title.x = element_text(size = 10))

Inter- vs trans-generational effects within and between disciplines
Merged_inter_vs_trans <- merge(Inter_vs_trans_info, Review_info)
count_inter_vs_trans <- Merged_inter_vs_trans %>%
count(inter_vs_trans_code, by = discipline_code) %>%
arrange(desc(n))
percent_inter_vs_trans <- count_inter_vs_trans %>%
mutate(percent = (n/sum(n)) * 100)
percent_inter_vs_trans <- percent_inter_vs_trans %>%
rename(discipline_code = by)
ggplot(percent_inter_vs_trans, aes(x = inter_vs_trans_code, y = percent)) + geom_col(aes(fill = discipline_code),
width = 0.7) + theme_light() + coord_flip() + scale_y_continuous(name = "Percent") +
theme(legend.position = "bottom", axis.title.x = element_text(size = 10), axis.title.y = element_blank()) +
guides(fill = guide_legend(title = "Discipline:"))

Table showing the controlled vacabularly used and a description of what the controlled vocabulary means.
Note that the description often equals controlled vocab but this is not always the case for more complicated elements.
Inter_vs_trans_info_unique <- Inter_vs_trans_code_info %>%
select(controlled_vocab_inter_vs_trans, description)
unique(Inter_vs_trans_info_unique)
## # A tibble: 3 x 2
## controlled_vocab_inter_vs_trans description
## <chr> <chr>
## 1 inter inter-generational
## 2 trans trans-generational
## 3 unclear unclear
Descendant generations within and between disciplines
merged_descendant_generat <- merge(Descendant_generat_info, Review_info)
count_descendant_generat <- merged_descendant_generat %>%
count(descendant_generat_code, by = discipline_code) %>%
arrange(desc(n))
percent_descendant_generat <- count_descendant_generat %>%
mutate(percent = (n/sum(n)) * 100)
percent_descendant_generat <- percent_descendant_generat %>%
rename(discipline_code = by)
ggplot(percent_descendant_generat, aes(x = descendant_generat_code, y = percent)) +
geom_col(aes(fill = discipline_code), width = 0.7) + theme_light() + coord_flip() +
scale_y_continuous(name = "Percent") + theme(legend.position = "bottom", axis.title.x = element_text(size = 10),
axis.title.y = element_blank()) + guides(fill = guide_legend(title = "Discipline:"))

Terminology used within and between disciplines
I.e., does the use of inter- and trans-generational inheritance match our definitions (see Fig. 1)
count_terminology <- Review_info %>%
count(terminology_code, by = discipline_code) %>%
arrange(desc(n))
percent_terminology <- count_terminology %>%
mutate(percent = (n/sum(n)) * 100)
percent_terminology <- percent_terminology %>%
rename(discipline_code = by)
ggplot(percent_terminology, aes(x = terminology_code, y = percent)) + geom_col(aes(fill = discipline_code),
width = 0.7) + theme_light() + coord_flip() + scale_y_continuous(name = "Percent") +
theme(legend.position = "bottom", axis.title.x = element_text(size = 10), axis.title.y = element_blank()) +
guides(fill = guide_legend(title = "Discipline:"))

Table showing the controlled vacabularly used and a description of what the controlled vocabulary means.
Note that the description often equals controlled vocab but this is not always the case for more complicated elements.
terminology_code_unique <- Terminology_code_info %>%
select(controlled_vocab_terminology, description_terminology)
unique(terminology_code_unique)
## # A tibble: 4 x 2
## controlled_vocab_terminology description_terminology
## <chr> <chr>
## 1 yes yes
## 2 no no
## 3 not used does not use these terms
## 4 unclear unclear
Types of non-genetic transmission within and between disciplines
I.e., are the non-genetic effects conferred through the matriline or patriline etc.
Merged_transmission_info <- merge(Transmission_info, Review_info)
count_transmission <- Merged_transmission_info %>%
count(transmission_code, by = discipline_code) %>%
arrange(desc(n))
percent_transmission <- count_transmission %>%
mutate(percent = (n/sum(n)) * 100)
percent_transmission <- percent_transmission %>%
rename(discipline_code = by)
ggplot(percent_transmission, aes(x = transmission_code, y = percent)) + geom_col(aes(fill = discipline_code),
width = 0.7) + theme_light() + coord_flip() + scale_y_continuous(name = "Percent") +
theme(legend.position = "bottom", axis.title.x = element_text(size = 10), axis.title.y = element_blank()) +
guides(fill = guide_legend(title = "Discipline:"))

Table showing the controlled vacabularly used and a description of what the controlled vocabulary means.
Note that the description often equals controlled vocab but this is not always the case for more complicated elements.
Transmission_info_unique <- Transmission_code_info %>%
select(controlled_vocab_transmission, description)
unique(Transmission_info_unique)
## # A tibble: 4 x 2
## controlled_vocab_transmi… description
## <chr> <chr>
## 1 matriline matriline
## 2 patriline patriline
## 3 not separated not separated (i.e., the primary studies used do no…
## 4 unclear unclear/unspecefied
F0 environmental manipulations within and between disciplines
merged_F0_env <- merge(F0_env_info, Review_info)
count_F0_env <- merged_F0_env %>%
count(F0_env_code, by = discipline_code) %>%
arrange(desc(n))
percent_F0_env <- count_F0_env %>%
mutate(percent = (n/sum(n)) * 100)
percent_F0_env <- percent_F0_env %>%
rename(discipline_code = by)
ggplot(percent_F0_env, aes(x = F0_env_code, y = percent)) + geom_col(aes(fill = discipline_code),
width = 0.7) + theme_light() + coord_flip() + scale_y_continuous(name = "Percent") +
theme(legend.position = "bottom", axis.title.x = element_text(size = 10), axis.title.y = element_blank()) +
guides(fill = guide_legend(title = "Discipline:"))

Table showing the controlled vacabularly used and a description of what the controlled vocabulary means.
Note that the description often equals controlled vocab but this is not always the case for more complicated elements.
F0_env_info_unique <- F0_env_code_info %>%
select(controlled_vocab_F0_env, description)
unique(F0_env_info_unique)
## # A tibble: 9 x 2
## controlled_vocab_F0_e… description
## <chr> <chr>
## 1 diet diet
## 2 human induced human induced pollutant/toxin
## 3 environmental composi… natural variation in environmental composition (e.g., …
## 4 psychological stress psychological stress (e.g., post-natal separation)
## 5 temperature temperature
## 6 human health ‘human health’ related environments (e.g., tobacco, al…
## 7 population demographic differences in population demographics (e.g., populati…
## 8 light light and/or photoperiod
## 9 other other/unclear
Environmental effect direction within and between disciplines
I.e., are the effects of environment predicted to have negative, positive, or neutral effects on offspring phenotype
merged_env_eff <- merge(Env_eff_diection_info, Review_info)
count_env_eff <- merged_env_eff %>%
count(env_eff_direction_code, by = discipline_code) %>%
arrange(desc(n))
percent_env_eff <- count_env_eff %>%
mutate(percent = (n/sum(n)) * 100)
percent_env_eff <- percent_env_eff %>%
rename(discipline_code = by)
ggplot(percent_env_eff, aes(x = env_eff_direction_code, y = percent)) + geom_col(aes(fill = discipline_code),
width = 0.7) + theme_light() + coord_flip() + scale_y_continuous(name = "Percent") +
theme(legend.position = "bottom", axis.title.x = element_text(size = 10), axis.title.y = element_blank()) +
guides(fill = guide_legend(title = "Discipline:"))

Table showing the controlled vacabularly used and a description of what the controlled vocabulary means.
Note that the description often equals controlled vocab but this is not always the case for more complicated elements.
Env_eff_direction_info_unique <- Env_eff_direction_code_info %>%
select(controlled_vocab_env_eff_direction, description)
unique(Env_eff_direction_info_unique)
## # A tibble: 3 x 2
## controlled_vocab_env_eff_direction description
## <chr> <chr>
## 1 negative negative
## 2 positive positive
## 3 unclear unclear
F0 environmental exposure timing within and between disciplines
Note: We excluded SRs that solely focused on environmental exposures that occured when the F0 generation was a fetus (i.e., pre-natal). However, some broader SRs (i.e., eco evo SRs) included primary studies where the F0 generation was exposed pre-natally. This was therefore coded in our data.
merged_exposure_timing <- merge(Exposure_timing_info, Review_info)
count_exposure_timing <- merged_exposure_timing %>%
count(exposure_timing_code, by = discipline_code) %>%
arrange(desc(n))
percent_exposure_timing <- count_exposure_timing %>%
mutate(percent = (n/sum(n)) * 100)
percent_exposure_timing <- percent_exposure_timing %>%
rename(discipline_code = by)
ggplot(percent_exposure_timing, aes(x = exposure_timing_code, y = percent)) + geom_col(aes(fill = discipline_code),
width = 0.7) + theme_light() + coord_flip() + scale_y_continuous(name = "Percent") +
theme(legend.position = "bottom", axis.title.x = element_text(size = 10), axis.title.y = element_blank()) +
guides(fill = guide_legend(title = "Discipline:"))

Table showing the controlled vacabularly used, and a description of what the controlled vocabulary means.
Note that the description often equals controlled vocab but this is not always the case for more complicated elements.
Exposure_timing_info_unique <- Exposure_timing_code_info %>%
select(controlled_vocab_exposure_timing, description)
unique(Exposure_timing_info_unique)
## # A tibble: 5 x 2
## controlled_vocab_exposure_timing description
## <chr> <chr>
## 1 pre-natal pre-natally
## 2 post-natal post-natal before sexual maturity
## 3 post-sexual maturity after sexual maturity but before gestation
## 4 gestation during gestation
## 5 unclear other/unclear
Descendant traits within and between disciplines
merged_descendant_trait <- merge(Descendant_trait_info, Review_info)
count_descendant_trait <- merged_descendant_trait %>%
count(descendant_trait_code, by = discipline_code) %>%
arrange(desc(n))
percent_descendant_trait <- count_descendant_trait %>%
mutate(percent = (n/sum(n)) * 100)
percent_descendant_trait <- percent_descendant_trait %>%
rename(discipline_code = by)
ggplot(percent_descendant_trait, aes(x = descendant_trait_code, y = percent)) + geom_col(aes(fill = discipline_code),
width = 0.7) + theme_light() + coord_flip() + scale_y_continuous(name = "Percent") +
theme(legend.position = "bottom", axis.title.x = element_text(size = 10), axis.title.y = element_blank()) +
guides(fill = guide_legend(title = "Discipline:"))

Table showing the controlled vacabularly used and a description of what the controlled vocabulary means.
Note that the description often equals controlled vocab but this is not always the case for more complicated elements.
Descendant_trait_info_unique <- Descendant_trait_code_info %>%
select(controlled_vocab_descendant_trait, description)
unique(Descendant_trait_info_unique)
## # A tibble: 9 x 2
## controlled_vocab_descendan… description
## <chr> <chr>
## 1 physiological physiological (e.g., immune function, insulin lev…
## 2 morphological morphological (e.g., body size, adiposity, colour…
## 3 reproductive reproductive (e.g., fecundity and sexual trait me…
## 4 life history life-history (e.g., developmental rate, aging and…
## 5 survival descendant survival/aging (must be post-natally)
## 6 behavioural behavioural (e.g., response to stimuli, anxiety, …
## 7 molecular molecular (e.g., gene expression, DNA methylation…
## 8 health health and disease (e.g., disease prevalence )
## 9 unclear other/unclear
Descendant sex within and between disciplines
merged_descendant_sex <- merge(Descendant_sex_info, Review_info)
count_descendant_sex <- merged_descendant_sex %>%
count(descendant_sex_code, by = discipline_code) %>%
arrange(desc(n))
percent_descendant_sex <- count_descendant_sex %>%
mutate(percent = (n/sum(n)) * 100)
percent_descendant_sex <- percent_descendant_sex %>%
rename(discipline_code = by)
ggplot(percent_descendant_sex, aes(x = descendant_sex_code, y = percent)) + geom_col(aes(fill = discipline_code),
width = 0.7) + theme_light() + coord_flip() + scale_y_continuous(name = "Percent") +
theme(legend.position = "bottom", axis.title.x = element_text(size = 10), axis.title.y = element_blank()) +
guides(fill = guide_legend(title = "Discipline:"))

Table showing the controlled vacabularly used and a description of what the controlled vocabulary means.
Note that the description often equals controlled vocab but this is not always the case for more complicated elements.
Descendant_sex_info_unique <- Descendant_sex_code_info %>%
select(controlled_vocab_descendant_sex, description)
unique(Descendant_sex_info_unique)
## # A tibble: 3 x 2
## controlled_vocab_descendant_sex description
## <chr> <chr>
## 1 males males
## 2 females females
## 3 unclear unclear
Descendant age within and between disciplines
Note: We excluded SRs that solely focused on fetal traits in descendants. However, some broader SRs included primary studies that mearured fetal traits. This was therefore coeded in our data.
merged_descendant_age <- merge(Descendant_age_info, Review_info)
count_descendant_age <- merged_descendant_age %>%
count(descendant_age_code, by = discipline_code) %>%
arrange(desc(n))
percent_descendant_age <- count_descendant_age %>%
mutate(percent = (n/sum(n)) * 100)
percent_descendant_age <- percent_descendant_age %>%
rename(discipline_code = by)
ggplot(percent_descendant_age, aes(x = descendant_age_code, y = percent)) + geom_col(aes(fill = discipline_code),
width = 0.7) + theme_light() + coord_flip() + scale_y_continuous(name = "Percent") +
theme(legend.position = "bottom", axis.title.x = element_text(size = 10), axis.title.y = element_blank()) +
guides(fill = guide_legend(title = "Discipline:"))

Table showing the controlled vacabularly used and a description of what the controlled vocabulary means.
Note that the description often equals controlled vocab but this is not always the case for more complicated elements.
Descendant_age_info_unique <- Descendant_age_code_info %>%
select(controlled_vocab_descendant_age, description)
unique(Descendant_age_info_unique)
## # A tibble: 5 x 2
## controlled_vocab_descendant_… description
## <chr> <chr>
## 1 fetal fetal/embryonic
## 2 juvenile juvenile (post-embryonic/birth prior to sexual …
## 3 adult adult
## 4 ongoing ongoing
## 5 unclear other/unclear
Higher taxononmic groups within and between disciplines
Merged_higher_taxon <- merge(Higher_taxon_info, Review_info)
count_higher_taxon <- Merged_higher_taxon %>%
count(taxon_code, by = discipline_code) %>%
arrange(desc(n))
percent_higher_taxon <- count_higher_taxon %>%
mutate(percent = (n/sum(n)) * 100)
percent_higher_taxon <- percent_higher_taxon %>%
rename(discipline_code = by)
ggplot(percent_higher_taxon, aes(x = taxon_code, y = percent)) + geom_col(aes(fill = discipline_code),
width = 0.7) + theme_light() + coord_flip() + scale_y_continuous(name = "Percent") +
theme(legend.position = "bottom", axis.title.x = element_text(size = 10), axis.title.y = element_blank()) +
guides(fill = guide_legend(title = "Discipline:"))

Table showing the controlled vacabularly used and a description of what the controlled vocabulary means.
Note that the description often equals controlled vocab but this is not always the case for more complicated elements.
Higher_taxon_info_unique <- Taxon_code_info %>%
select(controlled_vocab_taxon, description)
unique(Higher_taxon_info_unique)
## # A tibble: 5 x 2
## controlled_vocab_taxon description
## <chr> <chr>
## 1 vertebrates vertebrates
## 2 invertebrates invertebrates
## 3 plants plants
## 4 other other
## 5 unclear unclear
Descendent generation vs terminology use across disciplines
Does the terminology used (i.e., inter- vs trans-generational) match our definition (based on generation, sex and taxa) within the descendant generations examined
generat_terminology <- merge(Descendant_generat_info, Review_info)
count_generat_terminology <- generat_terminology %>%
count(descendant_generat_code, by = terminology_code) %>%
arrange(desc(n))
percent_generat_terminology <- count_generat_terminology %>%
mutate(percent = (n/sum(n)) * 100)
percent_generat_terminology <- percent_generat_terminology %>%
rename(terminology_code = by)
ggplot(percent_generat_terminology, aes(x = descendant_generat_code, y = percent)) +
geom_col(aes(fill = terminology_code), width = 0.7) + theme_light() + coord_flip() +
scale_y_continuous(name = "Percent") + theme(legend.position = "bottom", axis.title.x = element_text(size = 10),
axis.title.y = element_blank()) + guides(fill = guide_legend(title = "Terminology:"))

Time trend of the number of SRs per year
Publication_info %>%
count(year) %>%
ggplot(aes(x = year, y = n)) + geom_area(fill = "#919191", alpha = 1) + geom_line(color = "skyblue",
size = 1) + geom_point(size = 1, color = "blue") + theme_minimal() + scale_x_continuous(name = "",
limits = c(2005, 2020)) + scale_y_continuous(name = "Article count", limits = c(0,
10)) + ggtitle("Publication year") + theme(plot.title = element_text(hjust = 0.5))

Adressing objective 3
- Conduct bibliometric analyses of co-author networks and common terminology use across and within disciplines.
The following visualisations allow us to view bibliometric patterns from data exported directly from scopus. We are able to view common keyword use, author networks, affiliations, and citation patterns.
Keyword matrix plot
NetMatrix_keywords <- biblioNetwork(bib, analysis = "co-occurrences", network = "keywords", sep = ";")
NetMatrix_keywords_plot <- networkPlot(NetMatrix_keywords, normalize = "association", n = 10, Title = "Keyword co-occurrences", type = "fruchterman",
size.cex = TRUE, size = 30, remove.multiple = F, edgesize = 10, labelsize = 3, label.cex = TRUE, edges.min = 2, cluster = "edge_betweenness")

Thematic map
map_thematic <- thematicMap(bib, field = "ID", n = 1000, minfreq = 5, stemming = FALSE, size = 0.5, n.labels = 1, repel = TRUE)
plot(map_thematic$map)

Author collaboration network
NetMatrix_authors <- biblioNetwork(bib, analysis = "collaboration", network = "authors", sep = ";")
NetMatrix_authors_plot <- networkPlot(NetMatrix_authors, n = 20, Title = "Author collaboration", type = "auto", size = 15, size.cex = TRUE,
edgesize = 10, labelsize = 1)

Country collaboration network
bib_sco2 <- metaTagExtraction(bib, Field = "AU_CO", sep = ";") #we need to extract countries from the affiliations first
# bib_sco2$AU_CO[1:10]
NetMatrix_country <- biblioNetwork(bib_sco2, analysis = "collaboration", network = "countries", sep = ";")
NetMatrix_country_plot <- networkPlot(NetMatrix_country, n = 50, Title = "Country collaboration", type = "auto", size = TRUE, remove.multiple = FALSE,
labelsize = 1.5)

Addressing objective 4
- Conduct a critical appraisal of the SR literature to assess the rigour, transparency, and risk of bias.
The following visualisations allow us to see the average scores across each CEESAT questions as well as how each individual SR scored for each CEESAT questions. This will allow us to assess the quality and Risk of Bias of the SR literature.
Note: CEESAT questions and scoring criteria can be found in Appendix_S3 on the open Science Framework https://osf.io/detvk/.
CEESAT score summary across SRs
This plot shows the average CEESAT score per question. CEESAT questions and scoring criteria can be found in Appendix_S3 on the open Science Framework https://osf.io/detvk/.
# calculating the % of scores within each questions
count_ceesat_score <- ceesat_long %>%
count(score, by = question)
percent_ceesat_score <- count_ceesat_score %>%
mutate(percent = (n/sum(n)) * 100)
percent_ceesat_score <- percent_ceesat_score %>%
rename(question = by)
percent_ceesat_score$question <- as.factor(percent_ceesat_score$question)
percent_ceesat_score$question <- factor(percent_ceesat_score$question, levels(percent_ceesat_score$question)[length(percent_ceesat_score$question):1]) #reverse the order of questions
percent_ceesat_score$score <- as.factor(percent_ceesat_score$score)
percent_ceesat_score$score <- factor(percent_ceesat_score$score, levels(percent_ceesat_score$score)[c(2, 3, 1, 4)]) #set the order of levels for assessment scores:
summaryplot <- ggplot(data = percent_ceesat_score, x = question, y = percent) + geom_col(mapping = aes(x = question, y = percent, fill = score),
width = 0.7, position = "fill", color = "black") + coord_flip(ylim = c(0, 1)) + guides(fill = guide_legend(reverse = TRUE)) + scale_fill_manual(values = c("yellow",
"green", "orange", "red")) + theme(legend.position = "bottom", panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
panel.background = element_blank()) + ylab("Percent") + xlab("CEESAT question") + guides(fill = guide_legend(title = "Score:"))
summaryplot

Individual CEESAT Scores
This plot shows the CEESAT score per SR. CEESAT questions and scoring criteria can be found in Appendix_S3 on the open Science Framework https://osf.io/detvk/.
scoresplot <- ggplot(data = ceesat_long, aes(y = id, x = question)) + geom_tile(color = "black", fill = "white", size = 0.8) + geom_point(aes(color = as.factor(score)),
size = 5) + scale_x_discrete(position = "top") + guides(color = guide_legend(reverse = TRUE)) + scale_color_manual(values = c("orange",
"yellow", "green", "red"), name = "Score:") + theme_minimal() + theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
panel.background = element_blank(), legend.position = "bottom", legend.background = element_rect(linetype = "solid", colour = "grey"),
legend.key.size = unit(0.75, "cm"), legend.text = element_text(size = 12), axis.text.y = element_text(size = 10, color = "black"),
axis.text.x = element_text(angle = 45, hjust = 0), plot.margin = unit(c(1, 1, 1, 0), "cm")) + ylab("Study ID") + xlab("CEESAT question")
scoresplot

LS0tCnRpdGxlOiAiTm9uZ2VuZXRpYyBpbmhlcnRhbmNlIG1hcCBvZiBzeXN0ZW1hdGljIHJldmlld3MiCmF1dGhvcjogIkVyaW4gTWFjYXJ0bmV5LCBTenltZWsgRHJvYm5pYWssIFNoaW5pY2hpIE5ha2FnYXdhLCBNYWxnb3J6YXRhIExhZ2lzeiIKb3V0cHV0OiAKICAgIAogICAgcm1kZm9ybWF0czo6cmVhZHRoZWRvd246CiAgICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICAgIHRvY19kZXB0aDogNAplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGNvbnNvbGUKLS0tCiAgICAKYGBge3IsIGluY2x1ZGUgPSBGQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KAptZXNzYWdlID0gRkFMU0UsCndhcm5pbmcgPSBGQUxTRSwKY2FjaGUgPSBUUlVFLCAKdGlkeSA9IFRSVUUsIAplY2hvID0gVFJVRQopCgpybShsaXN0ID0gbHMoKSkKYGBgCgoKYGBge3Igc2V0dXAsIHJlc3VsdHMgPSAnaGlkZSd9Cgprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCgpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShwbHlyKQpsaWJyYXJ5KHRpYmJsZSkKbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeShrbml0cikKbGlicmFyeShmb3JjYXRzKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoaHJicnRoZW1lcykgI2ZvciBnZ3Bsb3QyCmxpYnJhcnkoYmlibGlvbWV0cml4KQpsaWJyYXJ5KGlncmFwaCkKCmBgYAojIyMgRGF0YSBsb2FkaW5nCgpgYGAge3IsIHJlc3VsdHMgPSAnaGlkZSd9CiNtYW51YWxseSBleHRyYWN0ZWQgZGF0YQp4bGRhdGEgPC0gIi4vRGF0YV9leHRyYWN0aW9uX3Bvc3Rjcm9zc2NoZWNraW5nLnhsc3giCgojYmlibGlvbWV0cmljIGRhdGEKYmliIDwtIGNvbnZlcnQyZGYoIi4vYmlibGlvbWV0cmljLmJpYiIsIGRic291cmNlID0gInNjb3B1cyIsIGZvcm1hdCA9ICJiaWJ0ZXgiKQpgYGAKCgojIyMgRGF0YSBvcmdhbmlzYXRpb24KU3BsaXR0aW5nIGxpc3Qgb2YgdGFicyBpbnRvIHNlcGFyYXRlIGRhdGFmcmFtZXMKCmBgYCB7ciwgcmVzdWx0cyA9ICdoaWRlJ30KCmV4Y2VsX3NoZWV0cyhwYXRoID0geGxkYXRhKQp0YWJfbmFtZXMgPC0gZXhjZWxfc2hlZXRzKHBhdGggPSB4bGRhdGEpCgoKI2NyZWF0aW5nIGEgbGlzdCBvZiBkYXRhZnJhbWVzIHBlciB0YWIKbGlzdF9hbGwgPC0gbGFwcGx5KHRhYl9uYW1lcywgZnVuY3Rpb24oeCkgcmVhZF9leGNlbChwYXRoID0geGxkYXRhLCBzaGVldCA9IHgpKQoKI2Fzc2lnbmluZyB0YWIgbmFtZXMgdG8gZWFjaCBkYXRhZnJhbWUKbmFtZXMobGlzdF9hbGwpIDwtIHRhYl9uYW1lcwoKI2dldCBkYXRhZnJhbWVzIG91dCBvZiBsaXN0Cmxpc3QyZW52KGxpc3RfYWxsLCAuR2xvYmFsRW52KQpgYGAKCiMjIEFkZHJlc3Npbmcgb2JqZWN0aXZlcyAxIGFuZCAyIHsudGFic2V0fQoKMSkJTWFwIHRoZSBTUiBsaXRlcmF0dXJlIGFjcm9zcyBkaXNjaXBsaW5lcyBlLmcuLCB0aGUgdHlwZXMgb2YgZW52aXJvbm1lbnRhbCBleHBvc3VyZXMgYW5kIHRyYWl0cyBzeW50aGVzaXNlZCwgdGhlIHByb3BvcnRpb24gb2YgU1JzIHRoYXQgZXhhbWluZSBpbnRlci0gdmVyc3VzIHRyYW5zLWdlbmVyYXRpb25hbCBlZmZlY3RzLCBhbmQgd2hpY2ggZGlzY2lwbGluZXMgZG9taW5hdGUgdGhlIG5vbi1nZW5ldGljIGluaGVyaXRhbmNlIFNSIGxpdGVyYXR1cmUuIFRoZSBtYXAgd2lsbCBoaWdobGlnaHQgZ2FwcyBpbiB0aGUgbGl0ZXJhdHVyZSB0aGF0IHJlbWFpbiB0byBiZSBzeW50aGVzaXNlZCBvciBoYXZlIHZlcnkgZmV3IFNScy4KCjIpCVByZXNlbnQgZGlzY2lwbGluZS1zcGVjaWZpYyByZXNlYXJjaCBwYXR0ZXJucyBieSBzdW1tYXJpc2luZyBjb21tb25hbGl0aWVzIGFuZCBkaXNwYXJpdGllcyBiZXR3ZWVuIGRpc2NpcGxpbmVzIChlLmcuLCBkbyBTUnMgb2Ygc3BlY2lmaWMgZW52aXJvbm1lbnRhbCBleHBvc3VyZXMgZG9taW5hdGUgb25lIGRpc2NpcGxpbmUgYW5kIG5vdCBvdGhlcnM/IERvIHNvbWUgZGlzY2lwbGluZXMgZm9jdXMgb24gaW50ZXItZ2VuZXJhdGlvbmFsIGVmZmVjdHMsIGFuZCBhbm90aGVyIG9uIHRyYW5zLWdlbmVyYXRpb25hbCBlZmZlY3RzPykuCgojIyMgUGVyY2VudCBvZiBTUidzIHdpdGhpbiBkaXNjaXBsaW5lcwoKYGBgIHtyfQoKY291bnRfZGlzY2lwbGluZSA8LVJldmlld19pbmZvICU+JSBjb3VudChkaXNjaXBsaW5lX2NvZGUpICU+JSBhcnJhbmdlKGRlc2MobikpIApwZXJjZW50X2Rpc2NpcGxpbmUgPC0gY291bnRfZGlzY2lwbGluZSAlPiUgbXV0YXRlKHBlcmNlbnQgPSAobi9zdW0obikpKjEwMCkKcGVyY2VudF9kaXNjaXBsaW5lJGRpc2NpcGxpbmVfY29kZSA8LSBmYWN0b3IocGVyY2VudF9kaXNjaXBsaW5lJGRpc2NpcGxpbmVfY29kZSwgbGV2ZWwgPSBwZXJjZW50X2Rpc2NpcGxpbmUkZGlzY2lwbGluZV9jb2RlW29yZGVyKHBlcmNlbnRfZGlzY2lwbGluZSRuLCBkZWNyZWFzaW5nID0gRkFMU0UpXSkKCmdncGxvdChwZXJjZW50X2Rpc2NpcGxpbmUsIGFlcyh4ID0gZGlzY2lwbGluZV9jb2RlLCB5ID0gcGVyY2VudCkpICsgCiAgZ2VvbV9jb2woYWVzKGZpbGwgPSAiIiksIHdpZHRoID0gMC43KSArIAogIHRoZW1lX2xpZ2h0KCkgKwogIGNvb3JkX2ZsaXAoKSArIAogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIlBlcmNlbnQiKSArCiAgeGxhYigiRGlzY2lwbGluZSIpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiIzkxOTE5MSIpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkKCmBgYAoKIyMjIEludGVyLSB2cyB0cmFucy1nZW5lcmF0aW9uYWwgZWZmZWN0cyB3aXRoaW4gYW5kIGJldHdlZW4gZGlzY2lwbGluZXMKCmBgYHtyfQoKTWVyZ2VkX2ludGVyX3ZzX3RyYW5zIDwtIG1lcmdlKEludGVyX3ZzX3RyYW5zX2luZm8sIFJldmlld19pbmZvKQoKY291bnRfaW50ZXJfdnNfdHJhbnMgPC0gTWVyZ2VkX2ludGVyX3ZzX3RyYW5zICU+JSBjb3VudChpbnRlcl92c190cmFuc19jb2RlLCBieSA9IGRpc2NpcGxpbmVfY29kZSApICU+JSBhcnJhbmdlKGRlc2MobikpCnBlcmNlbnRfaW50ZXJfdnNfdHJhbnMgPC0gY291bnRfaW50ZXJfdnNfdHJhbnMgJT4lIG11dGF0ZShwZXJjZW50ID0gKG4vc3VtKG4pKSoxMDApCgpwZXJjZW50X2ludGVyX3ZzX3RyYW5zIDwtcGVyY2VudF9pbnRlcl92c190cmFucyAlPiUKICByZW5hbWUoCiAgICBkaXNjaXBsaW5lX2NvZGUgPSBieQogICkKCmdncGxvdChwZXJjZW50X2ludGVyX3ZzX3RyYW5zLCBhZXMoeCA9IGludGVyX3ZzX3RyYW5zX2NvZGUsIHkgPSBwZXJjZW50KSkgKyAKICBnZW9tX2NvbChhZXMoZmlsbCA9IGRpc2NpcGxpbmVfY29kZSksIHdpZHRoID0gMC43KSArIAogIHRoZW1lX2xpZ2h0KCkgKwogIGNvb3JkX2ZsaXAoKSArIAogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIlBlcmNlbnQiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLCBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKHRpdGxlPSJEaXNjaXBsaW5lOiIpKQoKYGBgCgojIyMjIFRhYmxlIHNob3dpbmcgdGhlIGNvbnRyb2xsZWQgdmFjYWJ1bGFybHkgdXNlZCBhbmQgYSBkZXNjcmlwdGlvbiBvZiB3aGF0IHRoZSBjb250cm9sbGVkIHZvY2FidWxhcnkgbWVhbnMuIAoKTm90ZSB0aGF0IHRoZSBkZXNjcmlwdGlvbiBvZnRlbiBlcXVhbHMgY29udHJvbGxlZCB2b2NhYiBidXQgdGhpcyBpcyBub3QgYWx3YXlzIHRoZSBjYXNlIGZvciBtb3JlIGNvbXBsaWNhdGVkIGVsZW1lbnRzLgpgYGAge3J9CkludGVyX3ZzX3RyYW5zX2luZm9fdW5pcXVlIDwtIEludGVyX3ZzX3RyYW5zX2NvZGVfaW5mbyAlPiUgCiAgc2VsZWN0KAogIGNvbnRyb2xsZWRfdm9jYWJfaW50ZXJfdnNfdHJhbnMsIGRlc2NyaXB0aW9uCiAgKSAKdW5pcXVlKEludGVyX3ZzX3RyYW5zX2luZm9fdW5pcXVlKQpgYGAKCiMjIyBEZXNjZW5kYW50IGdlbmVyYXRpb25zIHdpdGhpbiBhbmQgYmV0d2VlbiBkaXNjaXBsaW5lcwoKYGBge3J9CgptZXJnZWRfZGVzY2VuZGFudF9nZW5lcmF0IDwtIG1lcmdlKERlc2NlbmRhbnRfZ2VuZXJhdF9pbmZvLCBSZXZpZXdfaW5mbykKCmNvdW50X2Rlc2NlbmRhbnRfZ2VuZXJhdCA8LSBtZXJnZWRfZGVzY2VuZGFudF9nZW5lcmF0ICU+JSBjb3VudChkZXNjZW5kYW50X2dlbmVyYXRfY29kZSwgYnkgPSBkaXNjaXBsaW5lX2NvZGUpICU+JSBhcnJhbmdlKGRlc2MobikpCnBlcmNlbnRfZGVzY2VuZGFudF9nZW5lcmF0IDwtIGNvdW50X2Rlc2NlbmRhbnRfZ2VuZXJhdCAlPiUgbXV0YXRlKHBlcmNlbnQgPSAobi9zdW0obikpKjEwMCkKCnBlcmNlbnRfZGVzY2VuZGFudF9nZW5lcmF0IDwtIHBlcmNlbnRfZGVzY2VuZGFudF9nZW5lcmF0ICU+JSAKICByZW5hbWUgKAogICAgZGlzY2lwbGluZV9jb2RlID0gYnkKICApCgpnZ3Bsb3QocGVyY2VudF9kZXNjZW5kYW50X2dlbmVyYXQsIGFlcyh4ID0gZGVzY2VuZGFudF9nZW5lcmF0X2NvZGUsIHkgPSBwZXJjZW50KSkgKyAKICBnZW9tX2NvbChhZXMoZmlsbCA9IGRpc2NpcGxpbmVfY29kZSksIHdpZHRoID0gMC43KSArIAogIHRoZW1lX2xpZ2h0KCkgKwogIGNvb3JkX2ZsaXAoKSArIAogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIlBlcmNlbnQiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLCBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKHRpdGxlPSJEaXNjaXBsaW5lOiIpKQoKYGBgCgojIyMgVGVybWlub2xvZ3kgdXNlZCB3aXRoaW4gYW5kIGJldHdlZW4gZGlzY2lwbGluZXMKSS5lLiwgZG9lcyB0aGUgdXNlIG9mIGludGVyLSBhbmQgdHJhbnMtZ2VuZXJhdGlvbmFsIGluaGVyaXRhbmNlIG1hdGNoIG91ciBkZWZpbml0aW9ucyAoc2VlIEZpZy4gMSkKCmBgYCB7cn0KCmNvdW50X3Rlcm1pbm9sb2d5IDwtIFJldmlld19pbmZvICU+JSBjb3VudCh0ZXJtaW5vbG9neV9jb2RlLCBieSA9IGRpc2NpcGxpbmVfY29kZSkgJT4lIGFycmFuZ2UoZGVzYyhuKSkKcGVyY2VudF90ZXJtaW5vbG9neSA8LSBjb3VudF90ZXJtaW5vbG9neSAlPiUgbXV0YXRlKHBlcmNlbnQgPSAobi9zdW0obikpKjEwMCkKCnBlcmNlbnRfdGVybWlub2xvZ3k8LSBwZXJjZW50X3Rlcm1pbm9sb2d5ICU+JQogIHJlbmFtZSgKICAgIGRpc2NpcGxpbmVfY29kZSA9IGJ5CiAgKQoKZ2dwbG90KHBlcmNlbnRfdGVybWlub2xvZ3ksIGFlcyh4ID0gdGVybWlub2xvZ3lfY29kZSwgeSA9IHBlcmNlbnQpKSArIAogIGdlb21fY29sKGFlcyhmaWxsID0gZGlzY2lwbGluZV9jb2RlKSwgd2lkdGggPSAwLjcpICsgCiAgdGhlbWVfbGlnaHQoKSArCiAgY29vcmRfZmxpcCgpICsgIAogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIlBlcmNlbnQiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLCBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKHRpdGxlPSJEaXNjaXBsaW5lOiIpKQoKYGBgCgojIyMjIFRhYmxlIHNob3dpbmcgdGhlIGNvbnRyb2xsZWQgdmFjYWJ1bGFybHkgdXNlZCBhbmQgYSBkZXNjcmlwdGlvbiBvZiB3aGF0IHRoZSBjb250cm9sbGVkIHZvY2FidWxhcnkgbWVhbnMuIAoKTm90ZSB0aGF0IHRoZSBkZXNjcmlwdGlvbiBvZnRlbiBlcXVhbHMgY29udHJvbGxlZCB2b2NhYiBidXQgdGhpcyBpcyBub3QgYWx3YXlzIHRoZSBjYXNlIGZvciBtb3JlIGNvbXBsaWNhdGVkIGVsZW1lbnRzLgpgYGAge3J9CnRlcm1pbm9sb2d5X2NvZGVfdW5pcXVlIDwtIFRlcm1pbm9sb2d5X2NvZGVfaW5mbyAlPiUgCiAgc2VsZWN0KAogICAgY29udHJvbGxlZF92b2NhYl90ZXJtaW5vbG9neSwgZGVzY3JpcHRpb25fdGVybWlub2xvZ3kKICApCnVuaXF1ZSh0ZXJtaW5vbG9neV9jb2RlX3VuaXF1ZSkKYGBgCgojIyMgVHlwZXMgb2Ygbm9uLWdlbmV0aWMgdHJhbnNtaXNzaW9uIHdpdGhpbiBhbmQgYmV0d2VlbiBkaXNjaXBsaW5lcwpJLmUuLCBhcmUgdGhlIG5vbi1nZW5ldGljIGVmZmVjdHMgY29uZmVycmVkIHRocm91Z2ggdGhlIG1hdHJpbGluZSBvciBwYXRyaWxpbmUgZXRjLgoKYGBge3J9CgpNZXJnZWRfdHJhbnNtaXNzaW9uX2luZm8gPC0gbWVyZ2UoVHJhbnNtaXNzaW9uX2luZm8sIFJldmlld19pbmZvKQoKY291bnRfdHJhbnNtaXNzaW9uIDwtIE1lcmdlZF90cmFuc21pc3Npb25faW5mbyAlPiUgIGNvdW50KHRyYW5zbWlzc2lvbl9jb2RlLCBieSA9IGRpc2NpcGxpbmVfY29kZSkgJT4lIGFycmFuZ2UoZGVzYyhuKSkKcGVyY2VudF90cmFuc21pc3Npb24gPC0gY291bnRfdHJhbnNtaXNzaW9uICU+JSBtdXRhdGUocGVyY2VudCA9IChuL3N1bShuKSkqMTAwKQoKcGVyY2VudF90cmFuc21pc3Npb24gPC1wZXJjZW50X3RyYW5zbWlzc2lvbiAlPiUKICByZW5hbWUoCiAgICBkaXNjaXBsaW5lX2NvZGUgPSBieQogICkKCmdncGxvdChwZXJjZW50X3RyYW5zbWlzc2lvbiwgYWVzKHggPSB0cmFuc21pc3Npb25fY29kZSwgeSA9IHBlcmNlbnQpKSArIAogIGdlb21fY29sKGFlcyhmaWxsID0gZGlzY2lwbGluZV9jb2RlKSwgd2lkdGggPSAwLjcpICsgCiAgdGhlbWVfbGlnaHQoKSArCiAgY29vcmRfZmxpcCgpICsgCiAgc2NhbGVfeV9jb250aW51b3VzKG5hbWUgPSAiUGVyY2VudCIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQodGl0bGU9IkRpc2NpcGxpbmU6IikpCgpgYGAKCiMjIyMgVGFibGUgc2hvd2luZyB0aGUgY29udHJvbGxlZCB2YWNhYnVsYXJseSB1c2VkIGFuZCBhIGRlc2NyaXB0aW9uIG9mIHdoYXQgdGhlIGNvbnRyb2xsZWQgdm9jYWJ1bGFyeSBtZWFucy4gCgpOb3RlIHRoYXQgdGhlIGRlc2NyaXB0aW9uIG9mdGVuIGVxdWFscyBjb250cm9sbGVkIHZvY2FiIGJ1dCB0aGlzIGlzIG5vdCBhbHdheXMgdGhlIGNhc2UgZm9yIG1vcmUgY29tcGxpY2F0ZWQgZWxlbWVudHMuCmBgYCB7cn0KVHJhbnNtaXNzaW9uX2luZm9fdW5pcXVlIDwtIFRyYW5zbWlzc2lvbl9jb2RlX2luZm8gJT4lIAogIHNlbGVjdCgKICAgIGNvbnRyb2xsZWRfdm9jYWJfdHJhbnNtaXNzaW9uLCBkZXNjcmlwdGlvbgogICkKdW5pcXVlKFRyYW5zbWlzc2lvbl9pbmZvX3VuaXF1ZSkgCgpgYGAKCiMjIyBGMCBlbnZpcm9ubWVudGFsIG1hbmlwdWxhdGlvbnMgd2l0aGluIGFuZCBiZXR3ZWVuIGRpc2NpcGxpbmVzCgpgYGB7cn0KCm1lcmdlZF9GMF9lbnYgPC0gbWVyZ2UoRjBfZW52X2luZm8sIFJldmlld19pbmZvKQoKY291bnRfRjBfZW52PC0gbWVyZ2VkX0YwX2VudiAlPiUgY291bnQoRjBfZW52X2NvZGUsIGJ5ID0gZGlzY2lwbGluZV9jb2RlICkgJT4lIGFycmFuZ2UoZGVzYyhuKSkKcGVyY2VudF9GMF9lbnYgPC0gY291bnRfRjBfZW52ICU+JSBtdXRhdGUocGVyY2VudCA9IChuL3N1bShuKSkqMTAwKQogCnBlcmNlbnRfRjBfZW52IDwtcGVyY2VudF9GMF9lbnYgJT4lCiAgcmVuYW1lKAogICAgZGlzY2lwbGluZV9jb2RlID0gYnkKICApCgpnZ3Bsb3QocGVyY2VudF9GMF9lbnYsIGFlcyh4ID0gRjBfZW52X2NvZGUsIHkgPSBwZXJjZW50KSkgKyAKICBnZW9tX2NvbChhZXMoZmlsbCA9IGRpc2NpcGxpbmVfY29kZSksIHdpZHRoID0gMC43KSArIAogIHRoZW1lX2xpZ2h0KCkgKwogIGNvb3JkX2ZsaXAoKSArIAogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIlBlcmNlbnQiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLCBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKHRpdGxlPSJEaXNjaXBsaW5lOiIpKQoKYGBgCgojIyMjIFRhYmxlIHNob3dpbmcgdGhlIGNvbnRyb2xsZWQgdmFjYWJ1bGFybHkgdXNlZCBhbmQgYSBkZXNjcmlwdGlvbiBvZiB3aGF0IHRoZSBjb250cm9sbGVkIHZvY2FidWxhcnkgbWVhbnMuIAoKTm90ZSB0aGF0IHRoZSBkZXNjcmlwdGlvbiBvZnRlbiBlcXVhbHMgY29udHJvbGxlZCB2b2NhYiBidXQgdGhpcyBpcyBub3QgYWx3YXlzIHRoZSBjYXNlIGZvciBtb3JlIGNvbXBsaWNhdGVkIGVsZW1lbnRzLgpgYGAge3J9CkYwX2Vudl9pbmZvX3VuaXF1ZSA8LSBGMF9lbnZfY29kZV9pbmZvICU+JSAKICBzZWxlY3QoCiAgICBjb250cm9sbGVkX3ZvY2FiX0YwX2VudiwgZGVzY3JpcHRpb24KICApCnVuaXF1ZShGMF9lbnZfaW5mb191bmlxdWUpCmBgYAoKIyMjIEVudmlyb25tZW50YWwgZWZmZWN0IGRpcmVjdGlvbiB3aXRoaW4gYW5kIGJldHdlZW4gZGlzY2lwbGluZXMKSS5lLiwgYXJlIHRoZSBlZmZlY3RzIG9mIGVudmlyb25tZW50IHByZWRpY3RlZCB0byBoYXZlIG5lZ2F0aXZlLCBwb3NpdGl2ZSwgb3IgbmV1dHJhbCBlZmZlY3RzIG9uIG9mZnNwcmluZyBwaGVub3R5cGUKCmBgYHtyfQoKbWVyZ2VkX2Vudl9lZmYgPC0gbWVyZ2UoRW52X2VmZl9kaWVjdGlvbl9pbmZvLCBSZXZpZXdfaW5mbykKCmNvdW50X2Vudl9lZmYgPC0gbWVyZ2VkX2Vudl9lZmYgJT4lIGNvdW50KGVudl9lZmZfZGlyZWN0aW9uX2NvZGUsIGJ5ID0gZGlzY2lwbGluZV9jb2RlKSAlPiUgYXJyYW5nZShkZXNjKG4pKQpwZXJjZW50X2Vudl9lZmYgPC0gY291bnRfZW52X2VmZiAlPiUgbXV0YXRlKHBlcmNlbnQgPSAobi9zdW0obikpKjEwMCkKCnBlcmNlbnRfZW52X2VmZiA8LXBlcmNlbnRfZW52X2VmZiAlPiUKICByZW5hbWUoCiAgICBkaXNjaXBsaW5lX2NvZGUgPSBieQogICkKCmdncGxvdChwZXJjZW50X2Vudl9lZmYsIGFlcyh4ID0gZW52X2VmZl9kaXJlY3Rpb25fY29kZSwgeSA9IHBlcmNlbnQpKSArIAogIGdlb21fY29sKGFlcyhmaWxsID0gZGlzY2lwbGluZV9jb2RlKSwgd2lkdGggPSAwLjcpICsgCiAgdGhlbWVfbGlnaHQoKSArCiAgY29vcmRfZmxpcCgpICsgCiAgc2NhbGVfeV9jb250aW51b3VzKG5hbWUgPSAiUGVyY2VudCIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQodGl0bGU9IkRpc2NpcGxpbmU6IikpCgpgYGAKCiMjIyMgVGFibGUgc2hvd2luZyB0aGUgY29udHJvbGxlZCB2YWNhYnVsYXJseSB1c2VkIGFuZCBhIGRlc2NyaXB0aW9uIG9mIHdoYXQgdGhlIGNvbnRyb2xsZWQgdm9jYWJ1bGFyeSBtZWFucy4gCgpOb3RlIHRoYXQgdGhlIGRlc2NyaXB0aW9uIG9mdGVuIGVxdWFscyBjb250cm9sbGVkIHZvY2FiIGJ1dCB0aGlzIGlzIG5vdCBhbHdheXMgdGhlIGNhc2UgZm9yIG1vcmUgY29tcGxpY2F0ZWQgZWxlbWVudHMuCmBgYCB7cn0KRW52X2VmZl9kaXJlY3Rpb25faW5mb191bmlxdWUgPC0gRW52X2VmZl9kaXJlY3Rpb25fY29kZV9pbmZvICU+JSAKICBzZWxlY3QoCiAgICBjb250cm9sbGVkX3ZvY2FiX2Vudl9lZmZfZGlyZWN0aW9uLCBkZXNjcmlwdGlvbgogICkKdW5pcXVlKEVudl9lZmZfZGlyZWN0aW9uX2luZm9fdW5pcXVlKSAKYGBgCgojIyMgRjAgZW52aXJvbm1lbnRhbCBleHBvc3VyZSB0aW1pbmcgd2l0aGluIGFuZCBiZXR3ZWVuIGRpc2NpcGxpbmVzCioqTm90ZToqKiBXZSBleGNsdWRlZCBTUnMgdGhhdCBzb2xlbHkgZm9jdXNlZCBvbiBlbnZpcm9ubWVudGFsIGV4cG9zdXJlcyB0aGF0IG9jY3VyZWQgd2hlbiB0aGUgRjAgZ2VuZXJhdGlvbiB3YXMgYSBmZXR1cyAoaS5lLiwgcHJlLW5hdGFsKS4gSG93ZXZlciwgIHNvbWUgYnJvYWRlciBTUnMgKGkuZS4sIGVjbyBldm8gU1JzKSBpbmNsdWRlZCBwcmltYXJ5IHN0dWRpZXMgd2hlcmUgdGhlIEYwIGdlbmVyYXRpb24gd2FzIGV4cG9zZWQgcHJlLW5hdGFsbHkuIFRoaXMgd2FzIHRoZXJlZm9yZSBjb2RlZCBpbiBvdXIgZGF0YS4gCgpgYGB7cn0KCm1lcmdlZF9leHBvc3VyZV90aW1pbmcgPC0gbWVyZ2UoRXhwb3N1cmVfdGltaW5nX2luZm8sIFJldmlld19pbmZvKQoKY291bnRfZXhwb3N1cmVfdGltaW5nIDwtIG1lcmdlZF9leHBvc3VyZV90aW1pbmcgJT4lIGNvdW50KGV4cG9zdXJlX3RpbWluZ19jb2RlLCBieSA9IGRpc2NpcGxpbmVfY29kZSkgJT4lIGFycmFuZ2UoZGVzYyhuKSkKcGVyY2VudF9leHBvc3VyZV90aW1pbmcgPC0gY291bnRfZXhwb3N1cmVfdGltaW5nICU+JSBtdXRhdGUocGVyY2VudCA9IChuL3N1bShuKSkqMTAwKQoKcGVyY2VudF9leHBvc3VyZV90aW1pbmcgPC1wZXJjZW50X2V4cG9zdXJlX3RpbWluZyAlPiUKICByZW5hbWUgKAogICAgZGlzY2lwbGluZV9jb2RlID0gYnkKICApCgpnZ3Bsb3QocGVyY2VudF9leHBvc3VyZV90aW1pbmcsIGFlcyh4ID0gZXhwb3N1cmVfdGltaW5nX2NvZGUsIHkgPSBwZXJjZW50KSkgKyAKICBnZW9tX2NvbChhZXMoZmlsbCA9IGRpc2NpcGxpbmVfY29kZSksIHdpZHRoID0gMC43KSArIAogIHRoZW1lX2xpZ2h0KCkgKwogIGNvb3JkX2ZsaXAoKSArIAogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIlBlcmNlbnQiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLCBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKHRpdGxlPSJEaXNjaXBsaW5lOiIpKQoKYGBgCgojIyMjIFRhYmxlIHNob3dpbmcgdGhlIGNvbnRyb2xsZWQgdmFjYWJ1bGFybHkgdXNlZCwgYW5kIGEgZGVzY3JpcHRpb24gb2Ygd2hhdCB0aGUgY29udHJvbGxlZCB2b2NhYnVsYXJ5IG1lYW5zLiAKCk5vdGUgdGhhdCB0aGUgZGVzY3JpcHRpb24gb2Z0ZW4gZXF1YWxzIGNvbnRyb2xsZWQgdm9jYWIgYnV0IHRoaXMgaXMgbm90IGFsd2F5cyB0aGUgY2FzZSBmb3IgbW9yZSBjb21wbGljYXRlZCBlbGVtZW50cy4KYGBgIHtyfQpFeHBvc3VyZV90aW1pbmdfaW5mb191bmlxdWU8LSBFeHBvc3VyZV90aW1pbmdfY29kZV9pbmZvICU+JSAKICBzZWxlY3QoCiAgICBjb250cm9sbGVkX3ZvY2FiX2V4cG9zdXJlX3RpbWluZywgZGVzY3JpcHRpb24KICApCnVuaXF1ZShFeHBvc3VyZV90aW1pbmdfaW5mb191bmlxdWUpIApgYGAKCiMjIyBEZXNjZW5kYW50IHRyYWl0cyB3aXRoaW4gYW5kIGJldHdlZW4gZGlzY2lwbGluZXMgCgpgYGB7cn0KCm1lcmdlZF9kZXNjZW5kYW50X3RyYWl0IDwtIG1lcmdlKERlc2NlbmRhbnRfdHJhaXRfaW5mbywgUmV2aWV3X2luZm8pCgpjb3VudF9kZXNjZW5kYW50X3RyYWl0IDwtIG1lcmdlZF9kZXNjZW5kYW50X3RyYWl0ICU+JSBjb3VudChkZXNjZW5kYW50X3RyYWl0X2NvZGUsIGJ5ID0gZGlzY2lwbGluZV9jb2RlKSAlPiUgYXJyYW5nZShkZXNjKG4pKQpwZXJjZW50X2Rlc2NlbmRhbnRfdHJhaXQgPC0gY291bnRfZGVzY2VuZGFudF90cmFpdCAlPiUgbXV0YXRlKHBlcmNlbnQgPSAobi9zdW0obikpKjEwMCkKCnBlcmNlbnRfZGVzY2VuZGFudF90cmFpdCA8LSBwZXJjZW50X2Rlc2NlbmRhbnRfdHJhaXQgJT4lCiAgcmVuYW1lKAogICAgZGlzY2lwbGluZV9jb2RlID0gYnkKICApCgpnZ3Bsb3QocGVyY2VudF9kZXNjZW5kYW50X3RyYWl0LCBhZXMoeCA9IGRlc2NlbmRhbnRfdHJhaXRfY29kZSwgeSA9IHBlcmNlbnQpKSArIAogIGdlb21fY29sKGFlcyhmaWxsID0gZGlzY2lwbGluZV9jb2RlKSwgd2lkdGggPSAwLjcpICsgCiAgdGhlbWVfbGlnaHQoKSArIAogIGNvb3JkX2ZsaXAoKSArIAogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIlBlcmNlbnQiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLCBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKHRpdGxlPSJEaXNjaXBsaW5lOiIpKQoKYGBgCgojIyMjIFRhYmxlIHNob3dpbmcgdGhlIGNvbnRyb2xsZWQgdmFjYWJ1bGFybHkgdXNlZCBhbmQgYSBkZXNjcmlwdGlvbiBvZiB3aGF0IHRoZSBjb250cm9sbGVkIHZvY2FidWxhcnkgbWVhbnMuIAoKTm90ZSB0aGF0IHRoZSBkZXNjcmlwdGlvbiBvZnRlbiBlcXVhbHMgY29udHJvbGxlZCB2b2NhYiBidXQgdGhpcyBpcyBub3QgYWx3YXlzIHRoZSBjYXNlIGZvciBtb3JlIGNvbXBsaWNhdGVkIGVsZW1lbnRzLgpgYGAge3J9CkRlc2NlbmRhbnRfdHJhaXRfaW5mb191bmlxdWU8LURlc2NlbmRhbnRfdHJhaXRfY29kZV9pbmZvICU+JSAKICBzZWxlY3QoCiAgICAgY29udHJvbGxlZF92b2NhYl9kZXNjZW5kYW50X3RyYWl0LGRlc2NyaXB0aW9uCiAgKQp1bmlxdWUoRGVzY2VuZGFudF90cmFpdF9pbmZvX3VuaXF1ZSkgCmBgYAoKIyMjIERlc2NlbmRhbnQgc2V4IHdpdGhpbiBhbmQgYmV0d2VlbiBkaXNjaXBsaW5lcwoKYGBge3J9CgptZXJnZWRfZGVzY2VuZGFudF9zZXggPC0gbWVyZ2UoRGVzY2VuZGFudF9zZXhfaW5mbywgUmV2aWV3X2luZm8pCgpjb3VudF9kZXNjZW5kYW50X3NleCA8LSBtZXJnZWRfZGVzY2VuZGFudF9zZXggJT4lIGNvdW50KGRlc2NlbmRhbnRfc2V4X2NvZGUsIGJ5ID0gZGlzY2lwbGluZV9jb2RlKSAlPiUgYXJyYW5nZShkZXNjKG4pKQpwZXJjZW50X2Rlc2NlbmRhbnRfc2V4IDwtIGNvdW50X2Rlc2NlbmRhbnRfc2V4ICAlPiUgbXV0YXRlKHBlcmNlbnQgPSAobi9zdW0obikpKjEwMCkKCnBlcmNlbnRfZGVzY2VuZGFudF9zZXggPC0gcGVyY2VudF9kZXNjZW5kYW50X3NleCAlPiUKICByZW5hbWUoCiAgICBkaXNjaXBsaW5lX2NvZGUgPSBieQogICAgICAgICAgICkKCmdncGxvdChwZXJjZW50X2Rlc2NlbmRhbnRfc2V4LCBhZXMoeCA9IGRlc2NlbmRhbnRfc2V4X2NvZGUsIHkgPSBwZXJjZW50KSkgKyAKICBnZW9tX2NvbChhZXMoZmlsbCA9IGRpc2NpcGxpbmVfY29kZSksIHdpZHRoID0gMC43KSArIAogIHRoZW1lX2xpZ2h0KCkgKwogIGNvb3JkX2ZsaXAoKSArIAogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIlBlcmNlbnQiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLCBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKHRpdGxlPSJEaXNjaXBsaW5lOiIpKQoKYGBgCgojIyMjIFRhYmxlIHNob3dpbmcgdGhlIGNvbnRyb2xsZWQgdmFjYWJ1bGFybHkgdXNlZCBhbmQgYSBkZXNjcmlwdGlvbiBvZiB3aGF0IHRoZSBjb250cm9sbGVkIHZvY2FidWxhcnkgbWVhbnMuIAoKTm90ZSB0aGF0IHRoZSBkZXNjcmlwdGlvbiBvZnRlbiBlcXVhbHMgY29udHJvbGxlZCB2b2NhYiBidXQgdGhpcyBpcyBub3QgYWx3YXlzIHRoZSBjYXNlIGZvciBtb3JlIGNvbXBsaWNhdGVkIGVsZW1lbnRzLgpgYGAge3J9CkRlc2NlbmRhbnRfc2V4X2luZm9fdW5pcXVlPC0gRGVzY2VuZGFudF9zZXhfY29kZV9pbmZvJT4lIAogIHNlbGVjdCgKICAgIGNvbnRyb2xsZWRfdm9jYWJfZGVzY2VuZGFudF9zZXgsIGRlc2NyaXB0aW9uCiAgKQp1bmlxdWUoRGVzY2VuZGFudF9zZXhfaW5mb191bmlxdWUpCmBgYAoKIyMjIERlc2NlbmRhbnQgYWdlIHdpdGhpbiBhbmQgYmV0d2VlbiBkaXNjaXBsaW5lcwoqKk5vdGU6KiogV2UgZXhjbHVkZWQgU1JzIHRoYXQgc29sZWx5IGZvY3VzZWQgb24gZmV0YWwgdHJhaXRzIGluIGRlc2NlbmRhbnRzLiBIb3dldmVyLCBzb21lIGJyb2FkZXIgU1JzIGluY2x1ZGVkIHByaW1hcnkgc3R1ZGllcyB0aGF0IG1lYXJ1cmVkIGZldGFsIHRyYWl0cy4gVGhpcyB3YXMgdGhlcmVmb3JlIGNvZWRlZCBpbiBvdXIgZGF0YS4gCgpgYGB7cn0KCm1lcmdlZF9kZXNjZW5kYW50X2FnZSA8LSBtZXJnZShEZXNjZW5kYW50X2FnZV9pbmZvLCBSZXZpZXdfaW5mbykKCmNvdW50X2Rlc2NlbmRhbnRfYWdlIDwtIG1lcmdlZF9kZXNjZW5kYW50X2FnZSAlPiUgY291bnQoZGVzY2VuZGFudF9hZ2VfY29kZSwgYnkgPSBkaXNjaXBsaW5lX2NvZGUpICU+JSBhcnJhbmdlKGRlc2MobikpCnBlcmNlbnRfZGVzY2VuZGFudF9hZ2UgPC0gY291bnRfZGVzY2VuZGFudF9hZ2UgJT4lIG11dGF0ZShwZXJjZW50ID0gKG4vc3VtKG4pKSoxMDApCgpwZXJjZW50X2Rlc2NlbmRhbnRfYWdlIDwtIHBlcmNlbnRfZGVzY2VuZGFudF9hZ2UgJT4lCiAgcmVuYW1lKAogICAgZGlzY2lwbGluZV9jb2RlID0gYnkKICApCgpnZ3Bsb3QocGVyY2VudF9kZXNjZW5kYW50X2FnZSwgYWVzKHggPSBkZXNjZW5kYW50X2FnZV9jb2RlLCB5ID0gcGVyY2VudCkpICsgCiAgZ2VvbV9jb2woYWVzKGZpbGwgPSBkaXNjaXBsaW5lX2NvZGUpLCB3aWR0aCA9IDAuNykgKyAKICB0aGVtZV9saWdodCgpICsKICBjb29yZF9mbGlwKCkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMobmFtZSA9ICJQZXJjZW50IikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLCBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpKSArIAogIGd1aWRlcyhmaWxsPWd1aWRlX2xlZ2VuZCh0aXRsZT0iRGlzY2lwbGluZToiKSkKCmBgYAoKIyMjIyBUYWJsZSBzaG93aW5nIHRoZSBjb250cm9sbGVkIHZhY2FidWxhcmx5IHVzZWQgYW5kIGEgZGVzY3JpcHRpb24gb2Ygd2hhdCB0aGUgY29udHJvbGxlZCB2b2NhYnVsYXJ5IG1lYW5zLiAKCk5vdGUgdGhhdCB0aGUgZGVzY3JpcHRpb24gb2Z0ZW4gZXF1YWxzIGNvbnRyb2xsZWQgdm9jYWIgYnV0IHRoaXMgaXMgbm90IGFsd2F5cyB0aGUgY2FzZSBmb3IgbW9yZSBjb21wbGljYXRlZCBlbGVtZW50cy4KYGBgIHtyfQpEZXNjZW5kYW50X2FnZV9pbmZvX3VuaXF1ZTwtIERlc2NlbmRhbnRfYWdlX2NvZGVfaW5mbyAlPiUgCiAgc2VsZWN0KAogICAgY29udHJvbGxlZF92b2NhYl9kZXNjZW5kYW50X2FnZSwgZGVzY3JpcHRpb24KICApCnVuaXF1ZShEZXNjZW5kYW50X2FnZV9pbmZvX3VuaXF1ZSkgCmBgYAoKIyMjIEhpZ2hlciB0YXhvbm9ubWljIGdyb3VwcyB3aXRoaW4gYW5kIGJldHdlZW4gZGlzY2lwbGluZXMgCgpgYGAge3J9CgpNZXJnZWRfaGlnaGVyX3RheG9uIDwtIG1lcmdlKEhpZ2hlcl90YXhvbl9pbmZvLCBSZXZpZXdfaW5mbykKCmNvdW50X2hpZ2hlcl90YXhvbiA8LSBNZXJnZWRfaGlnaGVyX3RheG9uICU+JSBjb3VudCh0YXhvbl9jb2RlLCBieSA9IGRpc2NpcGxpbmVfY29kZSkgJT4lIGFycmFuZ2UoZGVzYyhuKSkKcGVyY2VudF9oaWdoZXJfdGF4b24gPC0gY291bnRfaGlnaGVyX3RheG9uICU+JSBtdXRhdGUocGVyY2VudCA9IChuL3N1bShuKSkqMTAwKQoKcGVyY2VudF9oaWdoZXJfdGF4b248LXBlcmNlbnRfaGlnaGVyX3RheG9uICU+JQogIHJlbmFtZSgKICAgIGRpc2NpcGxpbmVfY29kZSA9IGJ5CiAgKQoKZ2dwbG90KHBlcmNlbnRfaGlnaGVyX3RheG9uLCBhZXMoeCA9IHRheG9uX2NvZGUsIHkgPSBwZXJjZW50KSkgKyAKICBnZW9tX2NvbChhZXMoZmlsbCA9IGRpc2NpcGxpbmVfY29kZSksIHdpZHRoID0gMC43KSArIAogIHRoZW1lX2xpZ2h0KCkgKwogIGNvb3JkX2ZsaXAoKSArIAogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIlBlcmNlbnQiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLCBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKHRpdGxlPSJEaXNjaXBsaW5lOiIpKQoKYGBgCgojIyMjIFRhYmxlIHNob3dpbmcgdGhlIGNvbnRyb2xsZWQgdmFjYWJ1bGFybHkgdXNlZCBhbmQgYSBkZXNjcmlwdGlvbiBvZiB3aGF0IHRoZSBjb250cm9sbGVkIHZvY2FidWxhcnkgbWVhbnMuIAoKTm90ZSB0aGF0IHRoZSBkZXNjcmlwdGlvbiBvZnRlbiBlcXVhbHMgY29udHJvbGxlZCB2b2NhYiBidXQgdGhpcyBpcyBub3QgYWx3YXlzIHRoZSBjYXNlIGZvciBtb3JlIGNvbXBsaWNhdGVkIGVsZW1lbnRzLgpgYGAge3J9CkhpZ2hlcl90YXhvbl9pbmZvX3VuaXF1ZTwtIFRheG9uX2NvZGVfaW5mbyAlPiUgCiAgc2VsZWN0KAogICAgY29udHJvbGxlZF92b2NhYl90YXhvbiwgZGVzY3JpcHRpb24KICApCnVuaXF1ZShIaWdoZXJfdGF4b25faW5mb191bmlxdWUpCmBgYAoKIyMjIERlc2NlbmRlbnQgZ2VuZXJhdGlvbiB2cyB0ZXJtaW5vbG9neSB1c2UgYWNyb3NzIGRpc2NpcGxpbmVzCkRvZXMgdGhlIHRlcm1pbm9sb2d5IHVzZWQgKGkuZS4sIGludGVyLSB2cyB0cmFucy1nZW5lcmF0aW9uYWwpIG1hdGNoIG91ciBkZWZpbml0aW9uIChiYXNlZCBvbiBnZW5lcmF0aW9uLCBzZXggYW5kIHRheGEpIHdpdGhpbiB0aGUgIGRlc2NlbmRhbnQgZ2VuZXJhdGlvbnMgZXhhbWluZWQKCmBgYCB7cn0KCmdlbmVyYXRfdGVybWlub2xvZ3kgPC0gbWVyZ2UoRGVzY2VuZGFudF9nZW5lcmF0X2luZm8sIFJldmlld19pbmZvKQogIApjb3VudF9nZW5lcmF0X3Rlcm1pbm9sb2d5IDwtIGdlbmVyYXRfdGVybWlub2xvZ3kgJT4lIGNvdW50KGRlc2NlbmRhbnRfZ2VuZXJhdF9jb2RlLCBieSA9IHRlcm1pbm9sb2d5X2NvZGUpICU+JSBhcnJhbmdlKGRlc2MobikpCnBlcmNlbnRfZ2VuZXJhdF90ZXJtaW5vbG9neSA8LSBjb3VudF9nZW5lcmF0X3Rlcm1pbm9sb2d5ICU+JSBtdXRhdGUocGVyY2VudCA9IChuL3N1bShuKSkqMTAwKQoKcGVyY2VudF9nZW5lcmF0X3Rlcm1pbm9sb2d5PC1wZXJjZW50X2dlbmVyYXRfdGVybWlub2xvZ3kgJT4lCiAgcmVuYW1lKAogICAgdGVybWlub2xvZ3lfY29kZSA9IGJ5CiAgKQoKZ2dwbG90KHBlcmNlbnRfZ2VuZXJhdF90ZXJtaW5vbG9neSwgYWVzKHggPSBkZXNjZW5kYW50X2dlbmVyYXRfY29kZSwgeSA9IHBlcmNlbnQpKSArIAogIGdlb21fY29sKGFlcyhmaWxsID0gdGVybWlub2xvZ3lfY29kZSksIHdpZHRoID0gMC43KSArIAogIHRoZW1lX2xpZ2h0KCkgKwogIGNvb3JkX2ZsaXAoKSArIAogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIlBlcmNlbnQiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLCBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKHRpdGxlPSJUZXJtaW5vbG9neToiKSkKYGBgCgojIyMgVGltZSB0cmVuZCBvZiB0aGUgbnVtYmVyIG9mIFNScyBwZXIgeWVhcgoKYGBgIHtyfQoKUHVibGljYXRpb25faW5mbyAlPiUgY291bnQoeWVhcikgJT4lIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSBuKSkgKyAKICBnZW9tX2FyZWEoZmlsbCA9ICcjOTE5MTkxJywgYWxwaGEgPSAxKSArCiAgZ2VvbV9saW5lKGNvbG9yID0gJ3NreWJsdWUnLCBzaXplID0gMSkgKyAKICBnZW9tX3BvaW50KHNpemU9MSwgY29sb3IgPSAnYmx1ZScpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHNjYWxlX3hfY29udGludW91cyhuYW1lID0gIiIsIGxpbWl0cyA9IGMoMjAwNSwgMjAyMCkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobmFtZSA9ICJBcnRpY2xlIGNvdW50IiwgbGltaXRzID0gYygwLCAxMCkpICsKICBnZ3RpdGxlKCJQdWJsaWNhdGlvbiB5ZWFyIikgKyAKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKCmBgYAoKIyMgQWRyZXNzaW5nIG9iamVjdGl2ZSAzIHsudGFic2V0fQoKMykJQ29uZHVjdCBiaWJsaW9tZXRyaWMgYW5hbHlzZXMgb2YgY28tYXV0aG9yIG5ldHdvcmtzIGFuZCBjb21tb24gdGVybWlub2xvZ3kgdXNlIGFjcm9zcyBhbmQgd2l0aGluIGRpc2NpcGxpbmVzLiAKClRoZSBmb2xsb3dpbmcgdmlzdWFsaXNhdGlvbnMgYWxsb3cgdXMgdG8gdmlldyBiaWJsaW9tZXRyaWMgcGF0dGVybnMgZnJvbSBkYXRhIGV4cG9ydGVkIGRpcmVjdGx5IGZyb20gc2NvcHVzLiBXZSBhcmUgYWJsZSB0byB2aWV3IGNvbW1vbiBrZXl3b3JkIHVzZSwgYXV0aG9yIG5ldHdvcmtzLCBhZmZpbGlhdGlvbnMsIGFuZCBjaXRhdGlvbiBwYXR0ZXJucy4gCgojIyMgQXV0aG9yLCBjb3VudHJ5LCBhbmQgY2l0YXRpb24gc3VtbWFyeSBwbG90cwoKYGBgIHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgcmVzdWx0cyA9ICdoaWRlJ30KcmVzdWx0czEgPC0gYmlibGlvQW5hbHlzaXMoYmliKSAjcnVuIGJhc2ljIHN0YW5kYXJkIGRlc2NyaXB0aXZlIGFuYWx5c2lzIG9mIHRoZSBkYXRhc2V0IChkYXRhIGZyYW1lKQpzdW1tYXJ5KHJlc3VsdHMxLCBrID0gNywgcGF1c2UgPSBGLCB3aWR0aCA9IDEzMCkgI3Byb2R1Y2VzIGEgc2VxdWVuY2Ugb2Ygc3RhbmRhcmQgc3VtbWFyeSB0YWJsZXMgZGlzcGxheWVkIGluIHRoZSBjb25zb2xlCnBsb3QocmVzdWx0czEsIGsgPSA3LCBwYXVzZSA9IEYpCmBgYAoKIyMjIEtleXdvcmQgbWF0cml4IHBsb3QKCmBgYCB7ciwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9Ck5ldE1hdHJpeF9rZXl3b3JkcyA8LSBiaWJsaW9OZXR3b3JrKGJpYiwgYW5hbHlzaXMgPSAiY28tb2NjdXJyZW5jZXMiLCBuZXR3b3JrID0gImtleXdvcmRzIiwgc2VwID0gIjsiKQpOZXRNYXRyaXhfa2V5d29yZHNfcGxvdCA8LSBuZXR3b3JrUGxvdChOZXRNYXRyaXhfa2V5d29yZHMsIG5vcm1hbGl6ZT0iYXNzb2NpYXRpb24iLCBuID0gMTAsIFRpdGxlID0gIktleXdvcmQgY28tb2NjdXJyZW5jZXMiLCB0eXBlID0gImZydWNodGVybWFuIiwgc2l6ZS5jZXggPSBUUlVFLCBzaXplID0gMzAsIHJlbW92ZS5tdWx0aXBsZSA9IEYsIGVkZ2VzaXplID0gMTAsIGxhYmVsc2l6ZSA9IDMsIGxhYmVsLmNleCA9IFRSVUUsZWRnZXMubWluID0gMiwgY2x1c3RlciA9ICJlZGdlX2JldHdlZW5uZXNzIikKYGBgCgojIyMgVGhlbWF0aWMgbWFwCgpgYGAge3IsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQptYXBfdGhlbWF0aWMgPC0gdGhlbWF0aWNNYXAoYmliLCBmaWVsZCA9ICJJRCIsIG4gPSAxMDAwLCBtaW5mcmVxID0gNSwgc3RlbW1pbmcgPSBGQUxTRSwgc2l6ZSA9IDAuNSwgbi5sYWJlbHMgPSAxLCByZXBlbCA9IFRSVUUpCnBsb3QobWFwX3RoZW1hdGljJG1hcCkKYGBgCgojIyMgQXV0aG9yIGNvbGxhYm9yYXRpb24gbmV0d29yawoKYGBgIHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0KTmV0TWF0cml4X2F1dGhvcnMgPC0gYmlibGlvTmV0d29yayhiaWIsIGFuYWx5c2lzID0gImNvbGxhYm9yYXRpb24iLCAgbmV0d29yayA9ICJhdXRob3JzIiwgc2VwID0gIjsiKQpOZXRNYXRyaXhfYXV0aG9yc19wbG90IDwtIG5ldHdvcmtQbG90KE5ldE1hdHJpeF9hdXRob3JzLCAgbiA9IDIwLCBUaXRsZSA9ICJBdXRob3IgY29sbGFib3JhdGlvbiIsIHR5cGUgPSAiYXV0byIsIHNpemUgPSAxNSwgc2l6ZS5jZXggPSBUUlVFLCBlZGdlc2l6ZSA9IDEwLCBsYWJlbHNpemUgPSAxKSAKYGBgCgojIyMgQ291bnRyeSBjb2xsYWJvcmF0aW9uIG5ldHdvcmsKCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0KYmliX3NjbzIgPC0gbWV0YVRhZ0V4dHJhY3Rpb24oYmliLCBGaWVsZCA9ICJBVV9DTyIsIHNlcCA9ICI7IikgI3dlIG5lZWQgdG8gZXh0cmFjdCBjb3VudHJpZXMgZnJvbSB0aGUgYWZmaWxpYXRpb25zIGZpcnN0CiNiaWJfc2NvMiRBVV9DT1sxOjEwXQpOZXRNYXRyaXhfY291bnRyeSA8LSBiaWJsaW9OZXR3b3JrKGJpYl9zY28yLCBhbmFseXNpcyA9ICJjb2xsYWJvcmF0aW9uIiwgbmV0d29yayA9ICJjb3VudHJpZXMiLCBzZXAgPSAiOyIpCk5ldE1hdHJpeF9jb3VudHJ5X3Bsb3QgPC0gIG5ldHdvcmtQbG90KE5ldE1hdHJpeF9jb3VudHJ5LCBuID0gNTAsIFRpdGxlID0gIkNvdW50cnkgY29sbGFib3JhdGlvbiIsIHR5cGUgPSAiYXV0byIsIHNpemU9VFJVRSwgcmVtb3ZlLm11bHRpcGxlPUZBTFNFLCBsYWJlbHNpemU9MS41KQpgYGAKCiMjIEFkZHJlc3Npbmcgb2JqZWN0aXZlIDQKCjQpCUNvbmR1Y3QgYSBjcml0aWNhbCBhcHByYWlzYWwgb2YgdGhlIFNSIGxpdGVyYXR1cmUgdG8gYXNzZXNzIHRoZSByaWdvdXIsIHRyYW5zcGFyZW5jeSwgYW5kIHJpc2sgb2YgYmlhcy4gCgpUaGUgZm9sbG93aW5nIHZpc3VhbGlzYXRpb25zIGFsbG93IHVzIHRvIHNlZSB0aGUgYXZlcmFnZSBzY29yZXMgYWNyb3NzIGVhY2ggQ0VFU0FUIHF1ZXN0aW9ucyBhcyB3ZWxsIGFzIGhvdyBlYWNoIGluZGl2aWR1YWwgU1Igc2NvcmVkIGZvciBlYWNoIENFRVNBVCBxdWVzdGlvbnMuIFRoaXMgd2lsbCBhbGxvdyB1cyB0byBhc3Nlc3MgdGhlIHF1YWxpdHkgYW5kIFJpc2sgb2YgQmlhcyBvZiB0aGUgU1IgbGl0ZXJhdHVyZS4gCgoqKk5vdGU6KiogQ0VFU0FUIHF1ZXN0aW9ucyBhbmQgc2NvcmluZyBjcml0ZXJpYSBjYW4gYmUgZm91bmQgaW4gQXBwZW5kaXhfUzMgb24gdGhlIG9wZW4gU2NpZW5jZSBGcmFtZXdvcmsgaHR0cHM6Ly9vc2YuaW8vZGV0dmsvLgoKIyMjIEJsaW5kaW5nIHBhcGVyIElEIGFuZCB3cmFuZ2xpbmcgZGF0YSBpbnRvIGxvbmcgZm9ybWF0CgpQYXBlciBJRCB3YXMgYmxpbmRlZCBmb3IgdGhlIHBpbG90IGJ1dCB3aWxsIG5vdCBiZSBibGluZGVkIGZvciB0aGUgZnVsbCBzdHVkeQoKYGBge3J9CiNibGluZGluZyBhdXRob3JzCkFzc2Vzc21lbnQkaWQgPC0gcGFzdGUoIklEIiwgYygxOmxlbmd0aChBc3Nlc3NtZW50JGlkKSksIHNlcCA9ICIiKQojc2hvcnRlbmluZyBjb2x1bW4gbmFtZXMKbmFtZXMoQXNzZXNzbWVudCkgPC0gZ3N1YigiQ0VFU0FUXyIsICIiLCBuYW1lcyhBc3Nlc3NtZW50KSwgZml4ZWQgPSBUUlVFKQojc2VsZWN0aW5nIG9ubHkgdGhlIGNvbHVtbnMgd2l0aCBzY29yZXMKI3NlbGVjdGluZyBvbmx5IHRoZSBjb2x1bW5zIHdpdGggc2NvcmVzCkFzc2Vzc21lbnRfcmVkdWNlZCA8LSBzZWxlY3QoQXNzZXNzbWVudCwgYygiaWQiLCAhZW5kc193aXRoKCJfY29tbWVudCIpKSkKI3dyYW5nbGluZyBkYXRhIGludG8gbG9uZyBmb3JtYXQKY2Vlc2F0X2xvbmcgPC0gZ2F0aGVyKEFzc2Vzc21lbnRfcmVkdWNlZCwgcXVlc3Rpb24sIHNjb3JlLCBRMS4xOlE4LjEsIGZhY3Rvcl9rZXk9VFJVRSkKYGBgCgojIyMgQ0VFU0FUIHNjb3JlIHN1bW1hcnkgYWNyb3NzIFNScwpUaGlzIHBsb3Qgc2hvd3MgdGhlIGF2ZXJhZ2UgQ0VFU0FUIHNjb3JlIHBlciBxdWVzdGlvbi4gCkNFRVNBVCBxdWVzdGlvbnMgYW5kIHNjb3JpbmcgY3JpdGVyaWEgY2FuIGJlIGZvdW5kIGluIEFwcGVuZGl4X1MzIG9uIHRoZSBvcGVuIFNjaWVuY2UgRnJhbWV3b3JrIGh0dHBzOi8vb3NmLmlvL2RldHZrLy4KCmBgYCB7cn0KI2NhbGN1bGF0aW5nIHRoZSAlIG9mIHNjb3JlcyB3aXRoaW4gZWFjaCBxdWVzdGlvbnMgCmNvdW50X2NlZXNhdF9zY29yZSA8LSBjZWVzYXRfbG9uZyAlPiUgY291bnQoc2NvcmUsIGJ5ID0gcXVlc3Rpb24pIApwZXJjZW50X2NlZXNhdF9zY29yZSA8LSBjb3VudF9jZWVzYXRfc2NvcmUgJT4lIG11dGF0ZShwZXJjZW50ID0gKG4vc3VtKG4pKSoxMDApCnBlcmNlbnRfY2Vlc2F0X3Njb3JlIDwtIHBlcmNlbnRfY2Vlc2F0X3Njb3JlICU+JQogIHJlbmFtZSgKICAgIHF1ZXN0aW9uID0gYnkKICApCnBlcmNlbnRfY2Vlc2F0X3Njb3JlJHF1ZXN0aW9uIDwtIGFzLmZhY3RvcihwZXJjZW50X2NlZXNhdF9zY29yZSRxdWVzdGlvbikKcGVyY2VudF9jZWVzYXRfc2NvcmUkcXVlc3Rpb24gPC0gZmFjdG9yKHBlcmNlbnRfY2Vlc2F0X3Njb3JlJHF1ZXN0aW9uLCBsZXZlbHMocGVyY2VudF9jZWVzYXRfc2NvcmUkcXVlc3Rpb24pW2xlbmd0aChwZXJjZW50X2NlZXNhdF9zY29yZSRxdWVzdGlvbik6MV0pICNyZXZlcnNlIHRoZSBvcmRlciBvZiBxdWVzdGlvbnMKcGVyY2VudF9jZWVzYXRfc2NvcmUkc2NvcmUgPC0gYXMuZmFjdG9yKHBlcmNlbnRfY2Vlc2F0X3Njb3JlJHNjb3JlKQpwZXJjZW50X2NlZXNhdF9zY29yZSRzY29yZSA8LSBmYWN0b3IocGVyY2VudF9jZWVzYXRfc2NvcmUkc2NvcmUsIGxldmVscyhwZXJjZW50X2NlZXNhdF9zY29yZSRzY29yZSlbYygyLDMsMSw0KV0pICNzZXQgdGhlIG9yZGVyIG9mIGxldmVscyBmb3IgYXNzZXNzbWVudCBzY29yZXM6CnN1bW1hcnlwbG90IDwtIGdncGxvdChkYXRhID0gcGVyY2VudF9jZWVzYXRfc2NvcmUsIHggPSBxdWVzdGlvbiwgeSA9IHBlcmNlbnQpICsKICBnZW9tX2NvbChtYXBwaW5nID0gYWVzKHggPSBxdWVzdGlvbiwgeSA9IHBlcmNlbnQsIGZpbGwgPSBzY29yZSksIHdpZHRoID0gMC43LAogICAgICAgICAgIHBvc2l0aW9uID0gImZpbGwiLCBjb2xvciA9ICJibGFjayIpICsKICBjb29yZF9mbGlwKHlsaW0gPSBjKDAsIDEpKSArCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQocmV2ZXJzZSA9IFRSVUUpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygieWVsbG93IiwiZ3JlZW4iLCAib3JhbmdlIiwicmVkIikpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSxwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgeWxhYigiUGVyY2VudCIpICsgeGxhYigiQ0VFU0FUIHF1ZXN0aW9uIikgKwogIGd1aWRlcyhmaWxsPWd1aWRlX2xlZ2VuZCh0aXRsZT0iU2NvcmU6IikpIApzdW1tYXJ5cGxvdApgYGAKCiMjIyBJbmRpdmlkdWFsIENFRVNBVCBTY29yZXMgClRoaXMgcGxvdCBzaG93cyB0aGUgQ0VFU0FUIHNjb3JlIHBlciBTUi4KQ0VFU0FUIHF1ZXN0aW9ucyBhbmQgc2NvcmluZyBjcml0ZXJpYSBjYW4gYmUgZm91bmQgaW4gQXBwZW5kaXhfUzMgb24gdGhlIG9wZW4gU2NpZW5jZSBGcmFtZXdvcmsgaHR0cHM6Ly9vc2YuaW8vZGV0dmsvLgoKYGBgIHtyfQpzY29yZXNwbG90IDwtIGdncGxvdChkYXRhID0gY2Vlc2F0X2xvbmcsIGFlcyh5ID0gaWQsIHggPSBxdWVzdGlvbikpICsKICBnZW9tX3RpbGUoY29sb3I9ImJsYWNrIiwgZmlsbD0id2hpdGUiLCBzaXplID0gMC44KSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBhcy5mYWN0b3Ioc2NvcmUpKSwgc2l6ZSA9IDUpICsKICBzY2FsZV94X2Rpc2NyZXRlKHBvc2l0aW9uID0gInRvcCIpICsKICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQocmV2ZXJzZSA9IFRSVUUpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIm9yYW5nZSIsInllbGxvdyIsImdyZWVuIiwicmVkIiApLCBuYW1lID0gIlNjb3JlOiIpICsgCiAgdGhlbWVfbWluaW1hbCgpICsgCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QobGluZXR5cGUgPSAic29saWQiLCBjb2xvdXIgPSAiZ3JleSIpLAogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC43NSwgImNtIiksCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsIGNvbG9yID0gImJsYWNrIiksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3Q9MCksCiAgICAgICAgcGxvdC5tYXJnaW4gPSB1bml0KGMoMSwxLDEsMCksICJjbSIpCiAgKSArCiAgeWxhYigiU3R1ZHkgSUQiKSArIAogIHhsYWIoIkNFRVNBVCBxdWVzdGlvbiIpIApzY29yZXNwbG90CmBgYA==